---
title: Redis
description: 键值型数据库
---

## Redis 是什么？为什么这么快？

Redis 的全称是 REmote DIctionary Server，它用字典结构存储数据，也就是 key-value 类型的数据。

Redis 的查询效率非常高，根据官方的数据，Redis 每秒最多处理的请求可达到 10 万次。

Redis 这么快是因为：

Redis 采用 C 语言编写，采用 C 语言进行编写的好处是底层代码执行效率高，依赖性低，因为使用 C 语言开发的库没有太多的运行时（Runtime）依赖，而且系统兼容性好，稳定性高。

此外，Redis 是基于内存的数据库，这样可以避免磁盘 I/O，因此 Redis 也被成为是 缓存工具。

其次，数据结构简单，Redis 采用 Key-Value 方式进行存储，也就是采用 Hash 结构进行操作，数据的操作复杂度为 O(1).

还有就是 Redis 采用单进程单线程模型，这样做的好处就是避免了上下文切换和不必要的线程之间引起的资源竞争。

在技术上 Redis 还采用了 I/O 多路复用技术。这里的多路指的是多个 socket 网络连接，复用指的是复用同一个线程。采用多路 I/O 复用技术的好处是可以在同一个线程中处理多个 I/O 请求，尽量减少网络 I/O 的消耗，提升使用效率。

## Redis 的数据类型
相比 Memcached ，Redis 有一个非常大的优势，就是支持多种数据类型。Redis 支持的数据类型包括字符串（string）、哈希（hash）、列表（list）、集合（set）、有序集合（zset）等。

字符串类型是 Redis 提供的最基本的数据类型，对应的结构是 key-value。

```shell title='设置某个键的值和获取某个键的值'
43.136.173.173:0>set name wkq
"OK"
43.136.173.173:0>get name
"wkq"
```

哈希（hash）提供了字段和字段值的映射，对应的结构是 key-field-value。
```shell
43.136.173.173:0>hset user1 username wkq
"1"
43.136.173.173:0>hset user1 age 22
"1"
```
```shell title='同时设置多个值'
43.136.173.173:0>hmset user2 username zbb age 21
"OK"
```
```shell title='获取某个键的某个 field 字段值'
43.136.173.173:0>hget user2 username
"zbb"
```

```shell title='一次获取某个键的多个 field 值'
43.136.173.173:0>hmget user2 username age
1) "zbb"
2) "21"
```

字符串列表（list） 的底层是一个双向链表结构，所以我们向列表的两端添加元素，时间复杂度为 O(1) ,同时也可以获取列表中的某个字段。

如果想向列表左侧添加元素可以使用 LPUSH key value [...]，如果想向列表右侧添加元素可以使用 RPUSH key value [...]

同样，如果想要获取列表中某一片段的内容，使用 LRANGE key start stop 即可。
```shell
43.136.173.173:0>RPUSH heroList dianwei lvhu
"5"
43.136.173.173:0>LRANGE herolist 0 4

43.136.173.173:0>LRANGE heroList 0 4
1) "liubei"
2) "guanyu"
3) "zhangfei"
4) "dianwei"
5) "lvhu"
```


字符串集合（set）是字符串类型的无序集合，与列表（list）的区别在于集合中的元素是无序的，同时元素不能重复。

如果想要在集合中添加元素，可以使用 SADD key member [...],比如我们给 heroSet 集合添加
```shell
43.136.173.173:0>SADD heroSet zhangfei guanyu liubei dianwei
"4"
```

如果想在集合中删除元素，可以使用 SREM key member [...] ,比如我们从 heroSet 集合中删除 liubei dianwei 这两个元素，可以写成：
```shell
43.136.173.173:0>SREM heroSet liubei dianwei
"2"
```
如果想要获取集合中的所有元素，可以使用 SMEMBERS key ，比如我们想要获取 heroSet 集合中的所有元素，写成 SMEMBERS heroSet 即可。
```shell

43.136.173.173:0>SMEMBERS heroSet
1) "liubei"
2) "guanyu"
3) "zhangfei"
4) "dianwei"
```
如果想要判断集合中是否存在某个元素，可以使用 SISMEMBER key member 。
```shell title='判断 heroSet 集合中是否存在 zhagnfei 和 liubei'
43.136.173.173:0>SISMEMBER heroSet liubei
"1"
```
我们可以把有序字符串集合（Sorted Set，简称 ZSet），理解为集合的升级版。实际上 ZSET 是在集合的基础上增加了一个分数属性，这个属性在添加元素的时候可以被指定。每次指定后，ZSET 都会按照分数来自动排序，也就是说我们在给集合 key 添加 member 的时候，可以指定 score。

有序集合和列表有一定的相似性，比如这两种数据类型都是有序的，都可以获取某一范围内的元素。但它们在数据结构上有很大的不同，首先 列表 list 是通过双向链表实现的，在操作左右两侧的数据时会非常快，而对于中间数据的操作相对较慢。有序集合采用 hash 表的结构来实现，读取排序在中间部分的数据也会很快。同时有序集合可以通过 score 来完成元素位置的调整，列表要对元素位置进行调整会比较困难。

```shell
开发环境:1>ZADD heroScore 8341 zhangfei 7107 guanyu 6900 liubei 7516 dianwei 7344 lvbu
"5"
```
如果想要获取某个元素的分数，可以使用 ZSCORE key member。
```shell
开发环境:1>ZSCORE heroScore guanyu
"7107"
```
如果想删除一个或多个元素，可以使用 ZREM key member [member ...],比如我们想要删除 guanyu 这个元素，使用 ZREM heroScore guanyu 即可。

我们也可以获取某个范围的元素列表。如果想要分数从小到大进行排序，使用 ZRANGE key start stop [WITHSCORES],如果分数从大到小排序，使用 ZREVRANGE key start stop [WITHSCORES]。需要注意的是 WITHSCORES 是个可选项，如果使用 WITHSCORES 会将分数一同显示出来。



```shell

开发环境:1>ZRANGE heroScore 0 10
1) "liubei"
2) "lvbu"
3) "dianwei"
4) "zhangfei"
开发环境:1>ZREVRANGE heroScore 0 10
1) "zhangfei"
2) "dianwei"
3) "lvbu"
4) "liubei"
```


